﻿using System;
using System.Drawing;
using System.IO;
using NPOI.HSSF.UserModel;
using NPOI.HSSF.Util;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;

namespace Sys.Excel
{
    public sealed class NPOI_ExcelExporter : ExcelExporterBase<IWorkbook, ISheet, ICellStyle>
    {
        #region [ private ]

        private HSSFColor Get_HSSFColor(HSSFWorkbook workbook, Color color)
        {
            var palette = workbook.GetCustomPalette();
            var colour = palette.FindColor(color.R, color.G, color.B);

            if (colour == null)
            {
                colour = palette.FindSimilarColor(color.R, color.G, color.B);
            }

            if (colour == null)
            {
                try
                {
                    colour = palette.AddColor(color.R, color.G, color.B);
                }
                catch
                {
                }
            }

            return colour;
        }

        private ICell Get_Cell(ISheet sheet, int row, int col)
        {
            var sheet_row = sheet.GetRow(row);

            if (sheet_row == null)
            {
                sheet_row = sheet.CreateRow(row);
            }

            return sheet_row.GetCell(col) ?? sheet_row.CreateCell(col);
        }

        #endregion

        protected override IWorkbook CreateWorkBook(bool useOldVersion)
        {
            return useOldVersion ? new HSSFWorkbook() : (IWorkbook)new XSSFWorkbook();
        }

        protected override ISheet CreateWorkSheet(IWorkbook workbook, string name, Settings settings)
        {
            var sheet = name == null ? workbook.CreateSheet() : workbook.CreateSheet(name);
            sheet.DefaultRowHeight = 20 * 20;
            return sheet;
        }

        protected override ICellStyle SetCellStyle(IWorkbook workbook, ICellStyle style, CellStyle cellStyle)
        {
            style = workbook.CreateCellStyle();

            Enum.TryParse<HorizontalAlignment>(cellStyle.TextAlign.ToString(), out var h_align);

            style.Alignment = h_align;

            style.VerticalAlignment = VerticalAlignment.Center;

            var font = workbook.CreateFont();

            font.IsBold = cellStyle.FontWeight == CellStyle.FontBoldWeight.Bold;

            if (font is HSSFFont)
            {
                font.Color = (this.Get_HSSFColor((HSSFWorkbook)workbook, cellStyle.FgColor.Value) ?? new HSSFColor.White()).Indexed;
            }
            else if (font is XSSFFont)
            {
                (font as XSSFFont).SetColor(new XSSFColor(cellStyle.FgColor.Value));
            }

            style.SetFont(font);

            style.FillPattern = FillPattern.SolidForeground;

            if (style is HSSFCellStyle)
            {
                style.FillForegroundColor = (this.Get_HSSFColor((HSSFWorkbook)workbook, cellStyle.BgColor.Value) ?? new HSSFColor.White()).Indexed;
            }
            else if (style is XSSFCellStyle)
            {
                (style as XSSFCellStyle).FillForegroundColorColor = new XSSFColor(cellStyle.BgColor.Value);
            }

            style.BorderLeft = BorderStyle.Thin;
            style.BorderTop = BorderStyle.Thin;
            style.BorderRight = BorderStyle.Thin;
            style.BorderBottom = BorderStyle.Thin;

            return style;
        }

        protected override ICellStyle GetCellStyle(IWorkbook workbook, ISheet sheet, Settings settings, int row, int col)
        {
            return this.Get_Cell(sheet, row, col).CellStyle;
        }

        protected override void SetDefaultRowHeight(IWorkbook workbook, ISheet sheet, uint height)
        {
            sheet.DefaultRowHeight = (short)((height == 0 ? 25U : height) * 20U);
        }

        protected override void SetCell(
            IWorkbook workbook, ISheet sheet, int row,
            int col, Settings settings, ColNode node, object value, ICellStyle style,
            bool setValue = true, bool setStyle = true)
        {
            if (setValue || setStyle)
            {
                var sheet_cell = this.Get_Cell(sheet, row, col);

                if (setValue)
                {
                    sheet_cell.SetCellValue(value == null ? null : value.ToString());
                }

                if (setStyle)
                {
                    sheet_cell.CellStyle = style;
                }
            }
        }

        protected override void MergeCells(
            IWorkbook workbook, ISheet sheet, int startRow,
            int endRow, int startCol, int endCol, Settings settings)
        {
            if (!(startRow == endRow && startCol == endCol))
            {
                sheet.AddMergedRegion(new CellRangeAddress(startRow, endRow, startCol, endCol));
            }
        }

        protected override void FreezePane(IWorkbook workbook, ISheet sheet, int rowSplit, int colSplit)
        {
            sheet.CreateFreezePane(colSplit, rowSplit);
        }

        protected override void SetColumnsWidth(IWorkbook workbook, ISheet sheet, Settings settings, uint[] widthArray, int startCol)
        {
            for (int i = 0; i < settings.LeafNodes.Count; i++)
            {
                sheet.SetColumnWidth(startCol + i, (int)widthArray[i] * 256);
            }
        }

        protected override void AutoFillColumns(IWorkbook workbook, ISheet sheet, Settings settings, int startCol)
        {
            for (int i = 0; i < settings.LeafNodes.Count; i++)
            {
                sheet.AutoSizeColumn((int)startCol + i, true);
            }
        }

        protected override void Save(IWorkbook workbook, bool useOldVersion, Stream stream)
        {
            workbook.Write(stream);
        }

        protected override void CloseWorkBook(IWorkbook workbook)
        {
            workbook.Close();
        }
    }
}